#pragma once
#include "Comm.h"
#include "Atom.h"
#include "ThreadLock.h"

namespace COMM
{
	class COMM_API CommonRef
	{
	public:
		CommonRef(void* ptr);
		virtual ~CommonRef();
		void* ptr();
		int Release(bool delptr = true);
		int AddRef();
	protected:
		virtual void DeletePtr() = 0;
		AtomInt m_ref_count;
		void* m_ptr;
	};

	template <class T>
	class CommonPtrRef : public CommonRef
	{
	public:
		CommonPtrRef(T* ptr) :CommonRef(ptr) {}
	protected:
		virtual void DeletePtr() { if (NULL != m_ptr) { delete (T*)m_ptr; m_ptr = NULL; } }
	};


	class COMM_API SharedPtrImp
	{
	public:
		SharedPtrImp(CommonRef* ref);
		virtual ~SharedPtrImp();
		SharedPtrImp(const SharedPtrImp& rhs);
		SharedPtrImp& operator=(const SharedPtrImp& rhs);
		void Release();

	protected:
		void* ptr() const;
	private:
		CommonRef* m_ref;
	};

	class COMM_API ScopedPtrImp
	{
		MYLIB_NONCOPIED_CLASS(ScopedPtrImp);
	public:
		explicit ScopedPtrImp(CommonRef* ref);
		~ScopedPtrImp();
		void Release();
		
	protected:
		void* ptr() const;
		void* detach();
		void attach(CommonRef* ref);
	private:
		CommonRef* m_ref;
	};

	


	// NOT MT-Safe
	//
	template<class T, class D= CommonPtrRef<T> >
	class SharedPtr : public SharedPtrImp
	{
	public:
		SharedPtr(T* ptr=NULL)
			:SharedPtrImp(new D(ptr)){}
		T* get(){ return (T*)ptr();}
		const T* get() const{ return (T*)ptr();}
		T* operator->(){ return get();}
		const T* operator->() const{ return get();}
		operator T*(){ return get();}
		operator const T*() const{ return get();}
		bool operator==(const T* ptr) const { return (ptr == get());}
		bool operator!=(const T* ptr) const { return (ptr != get());}
	};


	// NOT MT-Safe
	//
	template<class T, class D= CommonPtrRef<T> >
	class ScopedPtr : public ScopedPtrImp
	{
	public:
		explicit ScopedPtr(T* ptr=NULL)
			:ScopedPtrImp(new D(ptr)){}
		// Must be released by yourself.
		T* Detach(){ return (T*)detach();}
		ScopedPtr& Attach(T* ptr){ attach(new D(ptr)); return *this;}
		ScopedPtr& operator=(T* ptr){ return Attach(ptr);}
		T* get(){ return (T*)ptr();}
		const T* get() const{ return (T*)ptr();}
		T* operator->(){ return get();}
		const T* operator->() const{ return get();}
		operator T*(){ return get();}
		operator const T*() const{ return get();}
		bool operator==(const T* ptr) const { return (ptr == get());}
		bool operator!=(const T* ptr) const { return (ptr != get());}
	};
	
}
	


